namespace C1.Win.C1FlexGrid
{
    using C1.Win.C1FlexGrid.Util;
    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Windows.Forms;

    internal class GridDataSource
    {
        internal IBindingList _bindingList;
        internal BindingMemberInfo _bindingMember;
        internal CurrencyManager _currencyManager;
        internal object _dataSource;
        private bool _editing;
        internal PropertyDescriptorCollection _props;
        internal C1FlexGridBase _view;

        internal void AddColumn(PropertyDescriptor pd)
        {
            Column column = this._view.Cols.Add();
            column.Caption = pd.DisplayName;
            column.Name = pd.Name;
            column.AllowEditing = !pd.IsReadOnly;
            column.DataType = pd.PropertyType;
            if ((column.DataType == typeof(byte[])) || typeof(IList).IsAssignableFrom(column.DataType))
            {
                column.Visible = column.AllowEditing = false;
            }
            if (typeof(Image).IsAssignableFrom(column.DataType))
            {
                column.AllowEditing = false;
            }
        }

        protected void BindGrid()
        {
            bool redraw = this._view._grid.Redraw;
            this._view._grid.Redraw = false;
            try
            {
                this._view.Rows.SetCount(this._view.Rows.Fixed, false);
                this._view.Rows.SetCount(this._view.Rows.Fixed + this._currencyManager.Count, false);
                this._view.Cols.Count = this._view.Cols.Fixed;
                foreach (PropertyDescriptor descriptor in this._props)
                {
                    this.AddColumn(descriptor);
                }
                this._view.Row = -1;
                this.PositionChanged(this, null);
                this._view.LeftCol = 0;
                this.UpdateSortGlyph();
                if (this._view.AutoResize)
                {
                    this._view.AutoSizeCols(20);
                }
            }
            finally
            {
                this._view._grid.Redraw = redraw;
                this._view.OnDataRefresh(new ListChangedEventArgs(ListChangedType.Reset, -1, -1));
            }
        }

        private void BindingListChanged(object sender, ListChangedEventArgs e)
        {
            RowCollection rows;
            int count;
            bool flag = false;
            switch (e.ListChangedType)
            {
                case ListChangedType.Reset:
                    break;

                case ListChangedType.ItemAdded:
                    rows = this._view.Rows;
                    count = this.GridRowIndex(e.NewIndex);
                    if (count < 0)
                    {
                        count = rows.Count;
                    }
                    rows.InsertInternal(count, false, false);
                    if (rows[rows.Count - 1].Index == this._currencyManager.Count)
                    {
                        flag = true;
                        goto Label_0298;
                    }
                    break;

                case ListChangedType.ItemDeleted:
                    count = this.GridRowIndex(e.NewIndex);
                    if (count < 0)
                    {
                        break;
                    }
                    this._view.Rows.RemoveInternal(count, false);
                    this.PositionChanged(this, null);
                    flag = true;
                    goto Label_0298;

                case ListChangedType.ItemMoved:
                {
                    count = this.GridRowIndex(e.NewIndex);
                    int indexOld = this.GridRowIndex(e.OldIndex);
                    if ((count < 0) || (indexOld < 0))
                    {
                        break;
                    }
                    this._view.Rows.MoveInternal(indexOld, count, false);
                    this.PositionChanged(this, null);
                    flag = true;
                    goto Label_0298;
                }
                case ListChangedType.ItemChanged:
                    count = this.GridRowIndex(e.NewIndex);
                    if (count < 0)
                    {
                        break;
                    }
                    this._view._grid.NotifyViews(GridChangedTypeEnum.RepaintCell, count, -1);
                    flag = true;
                    goto Label_0298;

                case ListChangedType.PropertyDescriptorAdded:
                    this._props = this._currencyManager.GetItemProperties();
                    this.AddColumn(this._props[this._props.Count - 1]);
                    flag = true;
                    goto Label_0298;

                case ListChangedType.PropertyDescriptorDeleted:
                {
                    PropertyDescriptorCollection descriptors = this._currencyManager.GetItemProperties();
                    int num3 = 0;
                    while (num3 < descriptors.Count)
                    {
                        if (!this._props[num3].Equals(descriptors[num3]))
                        {
                            break;
                        }
                        num3++;
                    }
                    Column column = this._view.Cols[this._props[num3].Name];
                    if (column != null)
                    {
                        this._view.Cols.Remove(column.Index);
                        this._props = descriptors;
                        flag = true;
                    }
                    goto Label_0298;
                }
                default:
                    goto Label_0298;
            }
            rows = this._view.Rows;
            bool redraw = this._view.Redraw;
            bool flag3 = rows.Count > rows.Fixed;
            try
            {
                this._view.Redraw = false;
                rows.SetCount(rows.Fixed, false);
                rows.SetCount(rows.Fixed + this._currencyManager.Count, false);
            }
            finally
            {
                this._view.Redraw = redraw;
            }
            this.PositionChanged(this, null);
            bool flag4 = rows.Count > rows.Fixed;
            if ((!flag3 && flag4) && this._view.AutoResize)
            {
                this._view.AutoSizeCols(20);
            }
            flag = true;
        Label_0298:
            this.UpdateSortGlyph();
            if (!flag)
            {
                this.RefreshData(this._view, true);
            }
            else
            {
                this._view.OnDataRefresh(e);
            }
        }

        internal int ColumnIndex(string name)
        {
            if (name == null)
            {
                return -1;
            }
            PropertyDescriptor descriptor = this._props[name];
            if (descriptor == null)
            {
                return -1;
            }
            return this._props.IndexOf(descriptor);
        }

        internal string ConvertToString(object data, int col)
        {
            return data.ToString();
        }

        private void CurrencyItemChanged(object sender, ItemChangedEventArgs e)
        {
            if (e.Index < 0)
            {
                if (this._bindingList != this._currencyManager.List)
                {
                    if ((this._bindingList != null) && this._bindingList.SupportsChangeNotification)
                    {
                        this._bindingList.ListChanged -= new ListChangedEventHandler(this.BindingListChanged);
                    }
                    this._bindingList = this._currencyManager.List as IBindingList;
                    if ((this._bindingList != null) && this._bindingList.SupportsChangeNotification)
                    {
                        this._bindingList.ListChanged += new ListChangedEventHandler(this.BindingListChanged);
                    }
                    ListChangedEventArgs args = new ListChangedEventArgs(ListChangedType.Reset, -1, -1);
                    this.BindingListChanged(this, args);
                }
            }
            else if ((this._bindingList == null) || !this._bindingList.SupportsChangeNotification)
            {
                ListChangedEventArgs args2 = new ListChangedEventArgs(ListChangedType.ItemChanged, e.Index, e.Index);
                this.BindingListChanged(this, args2);
            }
        }

        private void DataSourceDisposed(object sender, EventArgs e)
        {
            this.SetDataSource(null, new BindingMemberInfo(string.Empty), true);
        }

        internal object GetData(int row, int col)
        {
            object obj2 = null;
            try
            {
                row = this.RecordIndex(row);
                object component = this._currencyManager.List[row];
                obj2 = this._props[this._view.Cols[col].Name].GetValue(component);
            }
            catch (Exception exception)
            {
                this._view.OnGridError(row, col, exception, true);
            }
            return obj2;
        }

        internal BindingMemberInfo GetDataMember()
        {
            return this._bindingMember;
        }

        internal object GetDataSource()
        {
            return this._dataSource;
        }

        public int GetFirstVisibleRow()
        {
            return this.RecordIndex(this._view.TopRow);
        }

        public int GetVisibleRowCount()
        {
            return (this.RecordIndex(this._view.BottomRow) - this.RecordIndex(this._view.TopRow));
        }

        internal int GridRowIndex(int dataIndex)
        {
            if (dataIndex >= 0)
            {
                RowCollection rows = this._view.Rows;
                rows.Update();
                for (int i = dataIndex + rows.Fixed; i < rows.Count; i++)
                {
                    if (rows[i]._dataIndex == dataIndex)
                    {
                        return i;
                    }
                }
            }
            return -1;
        }

        internal void InsertAt(int indexNew)
        {
            this._currencyManager.AddNew();
            int indexOld = this._currencyManager.List.Count - 1;
            this.Move(indexOld, indexNew);
        }

        internal bool IsDataBound()
        {
            return (this._currencyManager != null);
        }

        internal void Move(int indexOld, int indexNew)
        {
            if (indexOld != indexNew)
            {
                object obj2 = this._currencyManager.List[indexOld];
                this._currencyManager.List.RemoveAt(indexOld);
                this._currencyManager.List.Insert(indexNew, obj2);
            }
        }

        internal void OnLostFocus()
        {
            try
            {
                if (this._editing)
                {
                    this._currencyManager.EndCurrentEdit();
                }
            }
            catch
            {
            }
            this._editing = false;
        }

        private void PositionChanged(object sender, EventArgs e)
        {
            int row = this._view.Row;
            int num2 = this.GridRowIndex(this._currencyManager.Position);
            if ((num2 >= 0) && (row != num2))
            {
                this._view.Select(num2, this._view.Col, true);
            }
        }

        internal int RecordIndex(int rowIndex)
        {
            if (rowIndex < 0)
            {
                return -1;
            }
            return this._view.Rows[rowIndex].DataIndex;
        }

        internal void RefreshData(C1FlexGridBase view, bool force)
        {
            this._view = view;
            this.SetDataSource(this._dataSource, this._bindingMember, force);
        }

        internal void RemoveAt(int index)
        {
            this._currencyManager.RemoveAt(index);
        }

        public void ScrollToRow(int firstVisibleRow, int rowCount)
        {
            int count = this._currencyManager.List.Count;
            if (rowCount != count)
            {
                firstVisibleRow *= count / rowCount;
            }
            if (firstVisibleRow >= count)
            {
                firstVisibleRow = count;
            }
            this._view.TopRow = this.GridRowIndex(firstVisibleRow);
            if (this.RecordIndex(this._view.TopRow) != this._currencyManager.Position)
            {
                this._currencyManager.Position = this._view.TopRow;
            }
        }

        internal bool SetData(int row, int col, object data)
        {
            bool flag = false;
            row = this.RecordIndex(row);
            object component = this._currencyManager.List[row];
            PropertyDescriptor descriptor = this._props[this._view.Cols[col].Name];
            try
            {
                descriptor.SetValue(component, data);
                flag = true;
            }
            catch
            {
            }
            if (!flag)
            {
                object obj3 = Types.Coerce(data, descriptor.PropertyType);
                if ((obj3 != null) || (data == null))
                {
                    try
                    {
                        this._props[this._view.Cols[col].Name].SetValue(component, obj3);
                        flag = true;
                    }
                    catch
                    {
                    }
                }
            }
            if (flag)
            {
                IEditableObject obj4 = component as IEditableObject;
                if (obj4 != null)
                {
                    obj4.BeginEdit();
                }
                this._editing = true;
            }
            return flag;
        }

        internal void SetDataBinding(C1FlexGridBase view, object dataSource, string dataMember)
        {
            this._view = view;
            object obj2 = this._dataSource;
            BindingMemberInfo info = this._bindingMember;
            try
            {
                this.SetDataSource(dataSource, new BindingMemberInfo(dataMember), false);
            }
            catch (Exception exception)
            {
                this._view.OnGridError(-1, -1, exception, true);
                this._dataSource = obj2;
                this._bindingMember = info;
            }
        }

        internal void SetDataMember(C1FlexGridBase view, string newVal)
        {
            this._view = view;
            BindingMemberInfo info = this._bindingMember;
            try
            {
                this.SetDataSource(this._dataSource, new BindingMemberInfo(newVal), false);
            }
            catch (Exception exception)
            {
                this._view.OnGridError(-1, -1, exception, true);
                this._bindingMember = info;
            }
        }

        internal void SetDataSource(C1FlexGridBase view, object newVal)
        {
            this._view = view;
            this.SetDataSource(newVal, this._bindingMember, false);
        }

        protected void SetDataSource(object ds, BindingMemberInfo bm, bool force)
        {
            bool flag = ds != this._dataSource;
            bool flag2 = !this._bindingMember.Equals(bm);
            if ((flag || flag2) || force)
            {
                if (this._view != null)
                {
                    this._view.FinishEditing(true);
                }
                if (this._dataSource is IComponent)
                {
                    ((IComponent) this._dataSource).Disposed -= new EventHandler(this.DataSourceDisposed);
                }
                this._dataSource = ds;
                this._bindingMember = bm;
                if (this._dataSource is IComponent)
                {
                    ((IComponent) this._dataSource).Disposed += new EventHandler(this.DataSourceDisposed);
                }
                CurrencyManager manager = null;
                IBindingList list = null;
                if (((ds != null) && (this._view.BindingContext != null)) && (ds != Convert.DBNull))
                {
                    manager = (CurrencyManager) this._view.BindingContext[ds, bm.BindingMember];
                    list = manager.List as IBindingList;
                }
                if ((this._currencyManager != manager) || (this._bindingList != list))
                {
                    if ((this._bindingList != null) && this._bindingList.SupportsChangeNotification)
                    {
                        this._bindingList.ListChanged -= new ListChangedEventHandler(this.BindingListChanged);
                    }
                    if (this._currencyManager != null)
                    {
                        this._currencyManager.PositionChanged -= new EventHandler(this.PositionChanged);
                        this._currencyManager.ItemChanged -= new ItemChangedEventHandler(this.CurrencyItemChanged);
                    }
                    this._currencyManager = manager;
                    this._bindingList = list;
                    if (this._currencyManager != null)
                    {
                        this._currencyManager.PositionChanged += new EventHandler(this.PositionChanged);
                        this._currencyManager.ItemChanged += new ItemChangedEventHandler(this.CurrencyItemChanged);
                    }
                    if ((this._bindingList != null) && this._bindingList.SupportsChangeNotification)
                    {
                        this._bindingList.ListChanged += new ListChangedEventHandler(this.BindingListChanged);
                    }
                }
                if ((this._currencyManager != null) && ((flag2 || flag) || force))
                {
                    this._props = this._currencyManager.GetItemProperties();
                    this.BindGrid();
                }
                if ((this._currencyManager == null) && (this._view != null))
                {
                    this._view._grid.NotifyViews(GridChangedTypeEnum.GridChanged);
                }
            }
        }

        internal bool Sort(int c1, int c2)
        {
            return this.Sort(SortFlags.UseColSort, c1, c2);
        }

        internal bool Sort(SortFlags order, int c1, int c2)
        {
            int num;
            DataView view = this._bindingList as DataView;
            if (view != null)
            {
                string str = string.Empty;
                for (num = c1; num <= c2; num++)
                {
                    Column column = this._view.Cols[num];
                    if (((column.DataType != typeof(byte[])) && (column.Name != null)) && (this._props[column.Name] != null))
                    {
                        SortFlags flags = (order == SortFlags.UseColSort) ? column.Sort : order;
                        if ((flags & (SortFlags.Descending | SortFlags.Ascending)) != SortFlags.None)
                        {
                            if (str.Length > 0)
                            {
                                str = str + ", ";
                            }
                            str = str + column.Name;
                            if ((flags & SortFlags.Descending) != SortFlags.None)
                            {
                                str = str + " DESC";
                            }
                        }
                    }
                }
                view.Sort = str;
                return true;
            }
            if ((this._bindingList == null) || !this._bindingList.SupportsSorting)
            {
                return false;
            }
            bool flag = false;
            for (num = c2; num >= c1; num--)
            {
                Column column2 = this._view._grid._cols[num];
                if (((column2.DataType != typeof(byte[])) && (column2.Name != null)) && (this._props[column2.Name] != null))
                {
                    SortFlags flags2 = (order == SortFlags.UseColSort) ? column2.Sort : order;
                    if ((flags2 & (SortFlags.Descending | SortFlags.Ascending)) != SortFlags.None)
                    {
                        ListSortDirection direction = ((flags2 & SortFlags.Ascending) != SortFlags.None) ? ListSortDirection.Ascending : ListSortDirection.Descending;
                        this._bindingList.ApplySort(this._props[column2.Name], direction);
                        flag = true;
                    }
                }
            }
            if (!flag)
            {
                this._bindingList.RemoveSort();
            }
            return true;
        }

        internal void ThrowInvalidAction()
        {
            throw new Exception("Invalid action when bound.");
        }

        internal void UpdateCursor()
        {
            int position = this._currencyManager.Position;
            int num2 = this.RecordIndex(this._view.Row);
            if ((num2 >= 0) && (position != num2))
            {
                try
                {
                    this._currencyManager.EndCurrentEdit();
                    this._currencyManager.Position = num2;
                }
                catch (Exception exception)
                {
                    this.PositionChanged(this, null);
                    this._view.OnGridError(this._view.Row, this._view.Col, exception, true);
                }
            }
        }

        internal bool UpdateSortGlyph()
        {
            GridModel model = this._view._grid;
            model._mouseSortCol = null;
            if (((this._bindingList == null) || !this._bindingList.SupportsSorting) || !this._bindingList.IsSorted)
            {
                return false;
            }
            PropertyDescriptor sortProperty = this._bindingList.SortProperty;
            if (sortProperty == null)
            {
                return false;
            }
            Column column = this._view.Cols[sortProperty.Name];
            if (column == null)
            {
                return false;
            }
            SortFlags order = (this._bindingList.SortDirection == ListSortDirection.Ascending) ? SortFlags.Ascending : SortFlags.Descending;
            model.ShowSortAt(order, column.Index);
            return true;
        }
    }
}

